package com.yxw.bamboo.core;

import com.yxw.bamboo.core.send.event.SendEventListenerFactory;
import com.yxw.bamboo.core.send.event.SqlEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

import java.util.*;


@Component
public class NetWorkMonitor implements Runnable {
    private final static Logger logger = LoggerFactory.getLogger(NetWorkMonitor.class);
    // 服务器
    protected ServerSocket server;
    // 监听本地端口
    //private int localPort = 1080;
    // 目标主机地址
    //private String remoteHostAddr = "0.0.0.0";
    // 目标主机端口
    //private int remoteHostPort = 3360;
    // 设置超时时间 30s
    protected static int TIMEOUT = 15;

    public int getLocalPort() {
        return this.networkContext.getLocalPort();
    }


    public String getRemoteHostAddr() {
        return this.networkContext.getRemoteHostAddr();
    }
    public int getRemoteHostPort() {
        return this.networkContext.getRemoteHostPort();
    }

    public NetworkContext getNetworkContext() {
        return networkContext;
    }

    public void setNetworkContext(NetworkContext networkContext) {
        this.networkContext = networkContext;
    }

    protected NetworkContext networkContext;

    @Autowired
    protected SendEventListenerFactory sendEventListenerFactory;
    // 客户端列表 用于删除失效连接和超时连接
    protected static HashMap<Socket, Date> clientList = new HashMap<>();

    public NetWorkMonitor() {

        //run();
    }
    public NetWorkMonitor(NetworkContext networkContext) throws IOException {
//        this.localPort = networkContext.getLocalPort();
//        this.remoteHostAddr = networkContext.getRemoteHostAddr();
//        this.remoteHostPort = networkContext.getRemoteHostPort();
//        this.networkContext =networkContext;
        //run();
    }

    @Override
    public void run() {
        String remoteHostInfoString="远程主机-----"+this.getRemoteHostAddr()+":"+this.getRemoteHostPort()+"----";
        try {

            this.server = new ServerSocket(this.networkContext.getLocalPort());
            logger.info(remoteHostInfoString+"开启本地端口 : " + this.networkContext.getLocalPort()+"成功");
            networkContext.setEnd();
        } catch (IOException e) {
            logger.info(remoteHostInfoString+"开启本地端口 : " + this.networkContext.getLocalPort()+"失败"+"--:error:"+e.getMessage());
            networkContext.setError();
            return;
        }
        // 自动清除失效连接和超时连接
        new Thread(new AutoDestroy()).start();
        while (true) {
            Socket socket = null;
            Socket remoteHost = null;
            try {
                socket = server.accept();
                logger.info("新的socket 进入:"+socket.hashCode());
                // 接收到请求就把socket扔进ap,value为刷新时间
                clientList.put(socket, new Date());
                String address = socket.getRemoteSocketAddress().toString();
                logger.info("新连接 ： " + address);
                // 建立与目标主机的连接
                remoteHost = new Socket(this.networkContext.getRemoteHostAddr(), this.networkContext.getRemoteHostPort());
                logger.info("连接地址 : " + this.networkContext.getRemoteHostAddr() + ":" + this.networkContext.getRemoteHostPort());
                // 端口转发

                //共享db数据信息
                DbInfo dbINfo=new DbInfo();
                SocketChannel localToRemoteChannel=new SocketChannel(SocketChannel.LOCAL_TO_REMOTE,socket.hashCode(),0,dbINfo,this.networkContext.getId());
                SocketChannel remoteToLocalChannel=new SocketChannel(SocketChannel.REMOTE_TO_LOCAL,socket.hashCode(),0,dbINfo,this.networkContext.getId());
                SqlEventListener sqlBeforeEventListener=sendEventListenerFactory.createBefore(this.networkContext);
                SqlEventListener sqlAfterEventListener=sendEventListenerFactory.createAfter(this.networkContext);

                new Thread(new NetPortForward(socket, remoteHost, remoteHost.getInputStream(), socket.getOutputStream()
                        ,remoteToLocalChannel,sqlBeforeEventListener,sqlAfterEventListener)).start();

                new Thread(new NetPortForward(socket, remoteHost, socket.getInputStream(), remoteHost.getOutputStream()
                        ,localToRemoteChannel,sqlBeforeEventListener,sqlAfterEventListener)).start();
            } catch (IOException e) {
                logger.error("连接异常");
                logger.error(e.getMessage());
                NetHelper.close(socket);
                NetHelper.close(remoteHost);
            }
        }
    }

    // 用于清除失效连接和超时连接
    protected class AutoDestroy implements Runnable {

        @Override
        public void run() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    List<Socket> list = new LinkedList<>();
                    logger.info("开始扫描失效与超时连接");
                    Date start = new Date();
                    for (Socket socket : clientList.keySet()) {
                        Date lastTime = clientList.get(socket);
                        long time = new Date().getTime() - lastTime.getTime();
                        if (socket.isClosed() || time / 1000 >= TIMEOUT) {
                            list.add(socket);
                        }
                    }
                    logger.info("找到" + list.size() + "个,用时 : " + (new Date().getTime() - start.getTime()) + "毫秒");
                    logger.info("开始清除失效与超时连接");
                    for (Socket socket : list) {
                        try {
                            clientList.remove(socket);
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    logger.info("当前连接数 : " + clientList.size());
                }
            }, 30 * 1000, 30 * 1000);
        }
    }


}
